const express = require('express');
const router = express.Router();
const fs = require('fs-extra');
const path = require('path');
const { v4: uuidv4 } = require('uuid');
const { createLogger, logService } = require('../utils/logger');
const { uploadToCloudStorage } = require('../utils/cloudStorageUploader');
const { createWebSocketHelper } = require('../utils/wsHelper');
const { 
  processAppPath, 
  generatePublicPath, 
  getProjectRoot, 
  getAppPath, 
  getAppDistPath 
} = require('../utils/pathHelper');
const { readJsonConfig, saveJsonConfig } = require('../utils/fileHelper');
const { exec } = require('child_process');
const dayjs = require('dayjs');
const utc = require('dayjs/plugin/utc');
const timezone = require('dayjs/plugin/timezone');
dayjs.extend(utc);
dayjs.extend(timezone);
const CHINA_TZ = 'Asia/Shanghai';
const chinaNow = () => dayjs().tz(CHINA_TZ).format('YYYY-MM-DD HH:mm:ss');

// 创建日志记录器
const logger = createLogger('deploy-api');

/**
 * 验证存储配置是否包含必要字段
 */
function validateStorageConfig(config) {
  if (!config) {
    return { 
      valid: false, 
      missingFields: ['整个配置对象缺失'],
      message: '存储配置不存在'
    };
  }
  
  const requiredFields = ['name', 'type', 'bucket', 'domain', 'accessKey', 'secretKey'];
  const missingFields = requiredFields.filter(field => !config[field]);
  
  if (missingFields.length > 0) {
    return {
      valid: false,
      missingFields,
      message: `存储配置缺少必要字段: ${missingFields.join(', ')}`
    };
  }
  
  return { valid: true };
}

// 获取项目根目录
const rootDir = getProjectRoot();

// 配置文件路径
const DEPLOY_CONFIG_FILE = path.join(__dirname, '../config/deploy-config.json');
const STORAGE_CONFIG_FILE = path.join(__dirname, '../config/storage-configs.json');

// 确保配置文件存在
if (!fs.existsSync(DEPLOY_CONFIG_FILE)) {
  fs.writeJSONSync(DEPLOY_CONFIG_FILE, {
    storageConfigId: "",
    basePath: "www/micro-frontend/",
    cacheControl: "default",
    parallel: true,
    overwrite: true,
    cleanOld: false,
    cdnDomain: ""
  }, { spaces: 2 });
  logger.info('创建了新的部署配置文件');
}

/**
 * 读取部署配置
 */
function readDeployConfig() {
  return readJsonConfig(DEPLOY_CONFIG_FILE, {
    storageConfigId: "",
    basePath: "www/micro-frontend/",
    cacheControl: "default",
    parallel: true,
    overwrite: true,
    cleanOld: false,
    cdnDomain: ""
  });
}

/**
 * 保存部署配置
 */
function saveDeployConfig(config) {
  return saveJsonConfig(DEPLOY_CONFIG_FILE, config);
}

/**
 * 读取存储配置
 */
function readStorageConfigs() {
  const data = readJsonConfig(STORAGE_CONFIG_FILE, { configs: [] });
  return data.configs || [];
}

/**
 * 获取存储配置
 */
function getStorageConfig(id) {
  const configs = readStorageConfigs();
  return configs.find(config => config.id === id);
}

/**
 * 获取部署配置
 */
router.get('/config', (req, res) => {
  try {
    const config = readDeployConfig();
    res.json({
      code: 200,
      message: '获取部署配置成功',
      data: config
    });
  } catch (error) {
    logger.error('获取部署配置失败:', error);
    res.status(500).json({
      code: 500,
      message: '获取部署配置失败',
      error: error.message
    });
  }
});

/**
 * 更新部署配置
 */
router.put('/config', (req, res) => {
  try {
    const currentConfig = readDeployConfig();
    const updatedConfig = { ...currentConfig, ...req.body };
    
    if (req.body.storageConfig) {
      updatedConfig.storageConfig = req.body.storageConfig;
      logger.info('更新了完整的存储配置');
    }
    
    saveDeployConfig(updatedConfig);
    
    res.json({
      code: 200,
      message: '更新部署配置成功',
      data: updatedConfig
    });
  } catch (error) {
    logger.error('更新部署配置失败:', error);
    res.status(500).json({
      code: 500,
      message: '更新部署配置失败',
      error: error.message
    });
  }
});

/**
 * 部署应用
 */
router.post('/app/:appName', async (req, res) => {
  const { appName } = req.params;
  const { 
    useAppPathReplacement = true,
    deployType = 'prod', // 部署类型：'prod' 或 'gray'
    version = null // 灰度版本号（灰度部署时必填）
  } = req.body || {};
  const deployId = uuidv4();
  
  // 获取Express应用实例和WebSocket命名空间
  const app = require('../server').app;
  const deployNamespace = app.get('deployNamespace');
  const wsHelper = createWebSocketHelper(deployNamespace);
  
  try {
    // 获取部署配置和存储配置
    const deployConfig = readDeployConfig();
    const storageConfig = deployConfig.storageConfig;
    
    // 验证存储配置
    const validation = validateStorageConfig(storageConfig);
    if (!validation.valid) {
      return res.status(400).json({
        code: 400,
        message: validation.message,
        data: { missingFields: validation.missingFields }
      });
    }
    
    // 立即返回响应，避免前端等待
    res.json({
      code: 200,
      message: '部署任务已开始',
      data: {
        deployId,
        appName,
        status: 'deploying',
        timestamp: chinaNow()
      }
    });
    
    // 发送部署开始事件
    wsHelper.sendDeployStart(deployId, appName, storageConfig);
    
    // 处理部署路径（支持灰度版本）
    const prefix = storageConfig.prefix || 'www/micro/apps/';
    const { path: deployPath } = processAppPath(
      deployConfig.basePath || prefix, 
      appName, 
      useAppPathReplacement,
      deployType,
      version
    );
    
    // 记录部署类型信息
    if (deployType === 'gray') {
      logger.info(`灰度部署: 应用=${appName}, 版本=${version}, 路径=${deployPath}`);
    } else {
      logger.info(`生产部署: 应用=${appName}, 路径=${deployPath}`);
    }
    
    // 确定publicPath - 优先使用应用特定的配置
    let publicPath;
    if (deployConfig.apps && deployConfig.apps[appName] && deployConfig.apps[appName].publicPath) {
      // 使用应用特定的publicPath
      publicPath = deployConfig.apps[appName].publicPath;
      logger.info(`使用应用特定的publicPath: ${publicPath}`);
    } else {
      // 使用默认的publicPath (应用的.env中可能定义了VITE_PUBLIC_PATH，构建时会自动使用)
      publicPath = generatePublicPath(deployPath);
      logger.info(`使用生成的默认publicPath: ${publicPath}`);
    }
    
    logger.info(`部署应用 ${appName}`, {
      storageConfigName: storageConfig.name,
      deployPath,
      publicPath
    });
    
    // 检查应用是否存在
    const appPath = getAppPath(appName);
    if (!fs.existsSync(appPath)) {
      throw new Error(`应用 ${appName} 不存在`);
    }
    
    // 构建应用
    logger.info(`开始构建应用 ${appName}，publicPath: ${publicPath}`);
    const buildCommand = `cd "${appPath}" && npx vite build`;
    
    const buildProcess = exec(buildCommand, {
      env: {
        ...process.env,
        VITE_PUBLIC_PATH: publicPath,
        NODE_ENV: 'production'
      }
    });
    
    // 监听构建输出
    buildProcess.stdout.on('data', (data) => {
      const log = data.toString().trim();
      if (log) {
        logger.info(`[${appName}] ${log}`);
        wsHelper.sendDeployLog(deployId, appName, log, 'info');
      }
    });
    
    buildProcess.stderr.on('data', (data) => {
      const log = data.toString().trim();
      if (log) {
        if (log.startsWith('(!)')) {
          logger.warn(`[${appName}] ${log}`);
          wsHelper.sendDeployLog(deployId, appName, log, 'warning');
        } else {
          logger.error(`[${appName}] ${log}`);
          wsHelper.sendDeployLog(deployId, appName, log, 'error');
        }
      }
    });
    
    // 等待构建完成
    await new Promise((resolve, reject) => {
      buildProcess.on('close', (code) => {
        if (code === 0) {
          logger.info(`应用 ${appName} 构建成功`);
          wsHelper.sendDeployLog(deployId, appName, '应用构建成功', 'success');
          resolve();
        } else {
          const error = `应用 ${appName} 构建失败，退出码: ${code}`;
          logger.error(error);
          wsHelper.sendDeployLog(deployId, appName, error, 'error');
          reject(new Error(error));
        }
      });
    });
    
    // 上传到云存储
    const distPath = path.join(appPath, 'dist');
    if (!fs.existsSync(distPath)) {
      throw new Error(`构建输出目录不存在: ${distPath}`);
    }
    
    logger.info(`开始上传应用 ${appName} 到云存储`);
    wsHelper.sendDeployLog(deployId, appName, '开始上传到云存储...', 'info');
    
    await uploadToCloudStorage(distPath, deployPath, storageConfig, deployNamespace, deployId);
    
    // 发送部署完成事件
    wsHelper.sendDeployComplete(deployId, appName, storageConfig, deployPath, publicPath);
    logger.info(`应用 ${appName} 部署完成`);
    
  } catch (error) {
    logger.error(`部署应用 ${appName} 失败:`, error);
    
    // 发送部署失败事件
    wsHelper.sendDeployError(deployId, appName, error);
  }
});

/**
 * 批量部署应用
 */
router.post('/batch', async (req, res) => {
  const { appNames, useAppPathReplacement = true } = req.body || {};
  if (!Array.isArray(appNames) || appNames.length === 0) {
    return res.status(400).json({ code: 400, message: 'appNames 必须为非空数组' });
  }
  
  // 获取部署配置和存储配置
  const deployConfig = readDeployConfig();
  const storageConfig = deployConfig.storageConfig;
  
  // 验证存储配置
  const validation = validateStorageConfig(storageConfig);
  if (!validation.valid) {
    return res.status(400).json({
      code: 400,
      message: validation.message,
      data: { missingFields: validation.missingFields }
    });
  }
  
  const results = [];
  for (const appName of appNames) {
    const fakeReq = { 
      ...req, 
      params: { appName }, 
      body: { useAppPathReplacement } 
    };
    
    let result;
    await new Promise((resolve) => {
      router.handle({ ...fakeReq, url: `/app/${appName}`, method: 'POST' }, {
        json: (data) => { result = data; resolve(); },
        status: (code) => ({ json: (data) => { result = data; resolve(); } })
      }, () => resolve());
    });
    
    results.push({ appName, ...result });
  }
  
  res.json({ code: 200, message: '批量部署完成', results });
});

/**
 * 兼容 /api/deploy/:appName 的 POST 路由，转发到 /app/:appName 逻辑
 */
router.post('/:appName', async (req, res, next) => {
  return router.handle({ ...req, url: `/app/${req.params.appName}`, method: 'POST' }, res, next);
});

/**
 * 获取部署日志
 */
router.get('/logs', (req, res) => {
  try {
    const { app, limit = 100, type } = req.query;
    
    const logs = logService.getLogs({
      app,
      type,
      limit: parseInt(limit, 10),
      category: 'deploy'
    });
    
    res.json({
      code: 200,
      message: '获取部署日志成功',
      data: logs
    });
  } catch (error) {
    logger.error('获取部署日志失败:', error);
    res.status(500).json({
      code: 500,
      message: '获取部署日志失败',
      error: error.message
    });
  }
});

/**
 * 清除部署日志
 */
router.delete('/logs', (req, res) => {
  try {
    const { app } = req.query;
    
    const success = logService.clearLogs({
      app,
      category: 'deploy'
    });
    
    if (success) {
      logger.info(app ? `清除应用 ${app} 的部署日志` : '清除所有部署日志');
      
      res.json({
        code: 200,
        message: app ? `清除应用 ${app} 的部署日志成功` : '清除所有部署日志成功'
      });
    } else {
      throw new Error('清除日志失败');
    }
  } catch (error) {
    logger.error('清除部署日志失败:', error);
    res.status(500).json({
      code: 500,
      message: '清除部署日志失败',
      error: error.message
    });
  }
});

module.exports = router; 